package logparser.bean;

import java.io.DataOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class ParserOpenChannel extends Parser implements IParser{
	private static final String LOG_TAG = "Asimov::";
	
	private File m_file_crcs;
	private DataOutputStream m_writer_crcs;
	private String m_filename_crcs = "crcs.csv";
	
	private File m_file_netlog;
	private DataOutputStream m_writer_netlog;
	private String m_filename_netlog = "netlog.csv";
	
	
	
	private File m_file_oce;
	private DataOutputStream m_writer_oce;
	private String m_filename_oce = "oce.csv";
	
	private File m_file_all;
	private DataOutputStream m_writer_all;
	private String m_filename_all = "all_log.csv";
	
	private String m_app_folder = "app_openchannel";
	private String m_csm_log_folder;
	
	
	private HashMap<String,Boolean> m_csm_map = new HashMap<String,Boolean>();
	private HashMap<String,String>  m_trx_map = new HashMap<String,String>();
	private HashMap<String,DataOutputStream> m_csm_out_stream = new HashMap<String,DataOutputStream>();
	
	
	
	class tagCRCS {
		private static final String CRCS_HEAD = "timestamp;"
				+ "clientAddress;"
				+ "formatType;"
				+ "formatVersion;"
				+ "fromApp;"
				+ "toApp;"
			    + "FromNet;"
			    + "ToNet;"
			    + "cacheBytesIn;"
			    + "cacheBytesOut;"
			    + "host;"
			    + "application;"
			    + "applicationStatus;"
			    + "operation;"
			    + "protocolStack;"
			    + "networkProtocolStack;"
			    + "networkInterface;"
			    + "responseDelay;"
			    + "responseDuration;"
			    + "requestId;"
			    + "subscriptionId;"
			    + "statusCode;"
			    + "errorCode;"
			    + "contentType;"
			    + "headerLength;"
			    + "contentLength;"
			    + "responseHash;"
			    + "analysisString;"
			    + "analysis;"
			    + "optimization;"
			    + "protocolDetection;"
			    + "destinationIp;"
			    + "destinationPort;"
			    + "redirectedToIp;"
			    + "redirectedToPort;"
			    + "sequenceNumber;"
			    + "requestDelay;"
			    + "radioAwarenessStatus;"
			    + "originatorId;"
			    + "csmCreationTime;"
			    + "clientSrcPort;"
			    + "cspSrcPort"
			    + "\n";
		
		public static final String CRCS_ADDR = "0-0-0";
		
		public String toCSVHead() {
			// TODO Auto-generated method stub
			return CRCS_HEAD.replaceAll(";",",");
		}
		public String toCSVFormat(ParserLine parse) {
			// TODO Auto-generated method stub
			return null;
		}
		
		
		
	};
	
	class tagCommon implements IParser{
		public String m_date = "";
		public String m_tz = "";
		public int m_origline = -1;
		public String m_type = "";
		public String m_component = "";
		public String m_pid = "";
		public String m_tid = "";
		public String m_level = "";
		public String m_class = "";
		public String m_function = "";
		public String m_file = "";
		public String m_line = "";
		public String m_error = "";
		public String m_csm = "";
		public String m_trx = "";
		public String m_msg = "";
		
		
		public String toCSVHead() {
			// TODO Auto-generated method stub
			return "date," 
					+ "component," 
					+ "pid," 
					+ "tid,"
					+ "file," 
					+ "line," 
					+ "msg,"
					+ "type," 
					+ "level," 
					+ "class," 
					+ "function," 
					+ "error," 
					+ "csm," 
					+ "trx," 
					+ "timezone," 
					+ "origline\n";
		}

		public String toCSVFormat(ParserLine parse) {
			
			if(m_msg.isEmpty()){
				return "";
			}
			// TODO Auto-generated method stub
			StringBuilder sb = new StringBuilder()
								.append(m_date).append(",")
								.append(m_component).append(",")
								.append(m_pid).append(",")
								.append(m_tid).append(",")
								.append(m_file).append(",")
								.append(m_line).append(",")
								.append(csvHandlerStr(m_msg)).append(",")
								.append(m_type).append(",")
								.append(m_level).append(",")
								.append(m_class).append(",")
								.append(m_function).append(",")
								.append(m_error).append(",")
								.append(csvIntToStr(m_csm)).append(",")
								.append(csvIntToStr(m_trx)).append(",")
								.append(m_tz).append(",")
								.append(m_origline)
								.append("\n")
								;
			
			return sb.toString();
		}
		
		
		private void getFileName(String fileline){
			String[] split = fileline.split(":");
			
			m_file = split[0];
			m_line = split[1];
		}
		
		// remove ()
		private String removeBracket(String input){
			return input.substring(1, input.length() - 1);
		}
		
		// remove []
		private String removeBrace(String input){
			return input.substring(1, input.length() - 1);
		}
		
		
		private boolean processJni(String line, ParserLine parsed) {
			Matcher matcher;
			String regStr;
			String left;

			String msg = parsed.getMsg();
			
			regStr = "(\\d+)/(\\d+)/(\\d+)\\s*(\\d+):(\\d+):(\\d+).(\\d+)(\\s+)";
			matcher = Pattern.compile(regStr).matcher(msg);
			if(!matcher.find()){
				System.out.println("none jni formated line at:" + m_origline);
				m_msg = msg;
				return true;
			}
			
			m_date = msg.substring(matcher.start(), matcher.end());
			left = msg.substring(matcher.end());
			
			regStr = "(\\S+)(\\s+)";
			matcher = Pattern.compile(regStr).matcher(left);
			if(!matcher.find()){
				System.out.println("none formated jni line at:" + m_origline);
				m_msg = msg;
			}else{
				m_tz = matcher.group(1);
				matcher.find();
				m_tid = matcher.group(1);
				matcher.find();
				m_level = removeBrace(matcher.group(1));
				matcher.find();
				m_file = removeBracket(matcher.group(1));
				getFileName(m_file);
				matcher.find();
				m_error = removeBracket(matcher.group(1));
				
				// skip - 
				if(matcher.find()){
					m_msg = left.substring(matcher.end());
				}else{
					m_msg = "";
				}
			}
			
			if(m_file.equals("report_service.cpp")){
				regStr = "(\\d+)-(\\d+)-(\\d+)\\s(\\d+):(\\d+):(\\d+).(\\d+)";
				matcher = Pattern.compile(regStr).matcher(m_msg);
				if(matcher.find()){
					boolean isNetlog = false;
					String crcs_date = m_msg.substring(matcher.start(),matcher.end());
					left = m_msg.substring(matcher.end());
					
					if(left.contains("netlog")){
						isNetlog = true;
					}
					
					try {
						m_writer_crcs.write((crcs_date + "," + tagCRCS.CRCS_ADDR + left + "\n").getBytes());
						m_writer_crcs.flush();
						if(isNetlog){
							m_writer_netlog.write((crcs_date + "," + tagCRCS.CRCS_ADDR + left + "\n").getBytes());
							m_writer_netlog.flush();
						}
					} catch (IOException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			}
			
			// extract TRX [] 
			regStr = "(TRX|HTRX)\\s*\\[(\\S+)\\]";
			matcher = Pattern.compile(regStr).matcher(m_msg);
			if(matcher.find()){
				m_trx = matcher.group(2);
			}
			
			
			
			// extract CSM [] 
			regStr = "CSM\\s*\\[(\\S+)\\]";
			matcher = Pattern.compile(regStr).matcher(m_msg);
			if(matcher.find()){
				String csmStr = matcher.group(1);
				m_csm = csmStr;
				m_csm_map.put(csmStr, Boolean.valueOf(true));
			}
			
			
			if(!m_trx.isEmpty() && !m_csm.isEmpty()){
				m_trx_map.put(m_trx, m_csm);
			}
			
			// find trx releated csm
			if(m_csm.isEmpty() && !m_trx.isEmpty()){
				String csm = m_trx_map.get(m_trx); 
				if(csm != null){
					m_csm = csm;
				}
			}
			
			// search csm
			if(m_csm.isEmpty()){
				for(String csmStr:m_csm_map.keySet()){
					if(m_msg.toLowerCase().contains(csmStr.toLowerCase())){
						m_csm = csmStr;
						break;
					}
				}
			}
			
			if(!m_csm.isEmpty()){
				try {
					addCsmOutputStream(m_csm,line);
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			
			
			return true;
		}
		
		
		private boolean processOCEngine(String line, ParserLine parsed, String className){
			Matcher matcher;
			String regStr;
			String left;

			String msg = parsed.getMsg();
			
			m_class = className;
			// no date flag
			regStr = "(\\d+)/(\\d+)/(\\d+)\\s*(\\d+):(\\d+):(\\d+).(\\d+)(\\s+)";
			matcher = Pattern.compile(regStr).matcher(msg);
			if(!matcher.find()){
				System.out.println("none formated oce line at:" + m_origline);
				m_msg = msg;
				return true;
			}
			
			m_date = msg.substring(matcher.start(), matcher.end());
			left = msg.substring(matcher.end());
			
			regStr = "(\\S+)(\\s+)";
			matcher = Pattern.compile(regStr).matcher(left);
			
			if(!matcher.find()){
				System.out.println("none formated oce line at:" + m_origline);
				m_msg = msg;
			}else{
				m_tz = matcher.group(1);
				matcher.find();
				m_tid = matcher.group(1);
				matcher.find();
				m_level = removeBrace(matcher.group(1));
				matcher.find();
				m_file = removeBracket(matcher.group(1));
				
				m_msg = left.substring(matcher.end());
				
				if(m_file.contains(":")){
					String[] split = m_file.split(":");
					m_file = split[0];
					m_line = split[1];
				}
				
				
				if(m_line.contains("@")){
					String[] split = m_line.split("@");
					m_line = split[0];
					m_function = split[1];
				}
			}
			
			return true;
		}
		
		public boolean processLine(String line, ParserLine parsed){
			String[] split = parsed.getTag().split("::");
			
			m_pid = parsed.getProcessId();
			m_origline = parsed.getOrigLine();
			
			if(parsed.getMsg().isEmpty()){
				return true;
			}
			
			if(split[1].equalsIgnoreCase("java")){
				m_type = "java";
				m_component = "OCEngine";
				
				processOCEngine(line,parsed,split[2]);
				
				try {
					m_writer_oce.write(this.toCSVFormat(parsed).getBytes());
					m_writer_all.write(this.toCSVFormat(parsed).getBytes());
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				
				return true;
				
			}else if(split[1].equalsIgnoreCase("Native")){
				m_type = "jni";
				m_component = split[2];
				processJni(line,parsed);
				
				try {
					m_writer_all.writeBytes(this.toCSVFormat(parsed));
					if(m_component.equals("OCEngine")){
						m_writer_oce.writeBytes(this.toCSVFormat(parsed));
					}
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				
				return true;
			}else{
				return false;
			}
			
		}
		
		
	}
	
	
	public String toCSVFormat(ParserLine parse) {
		// TODO Auto-generated method stub
		return null;
	}

	public String toCSVHead() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public void processStart() throws Exception{
		// TODO Auto-generated method stub
		String output_folder = m_output_folder + File.separator + m_app_folder + File.separator;
		new File(output_folder).mkdirs();
		
		m_csm_log_folder = output_folder + "csm_log" + File.separator;
		new File(m_csm_log_folder).delete();
		new File(m_csm_log_folder).mkdirs();
		
		
		m_file_crcs = new File(output_folder + m_filename_crcs);
		m_file_netlog = new File(output_folder + m_filename_netlog);
		
		m_file_oce = new File(output_folder + m_filename_oce);
		m_file_all = new File(output_folder + m_filename_all);
		
		
		
		m_writer_crcs = new DataOutputStream(new FileOutputStream(m_file_crcs));
		m_writer_netlog = new DataOutputStream(new FileOutputStream(m_file_netlog));
		m_writer_oce = new DataOutputStream(new FileOutputStream(m_file_oce));
		m_writer_all = new DataOutputStream(new FileOutputStream(m_file_all));
		
	
		m_writer_crcs.write(utf8Head);
		m_writer_crcs.write(new tagCRCS().toCSVHead().getBytes());
		
		m_writer_netlog.write(utf8Head);
		m_writer_netlog.write(new tagCRCS().toCSVHead().getBytes());
		
		
		m_writer_oce.write(utf8Head);
		m_writer_oce.write(new tagCommon().toCSVHead().getBytes());
		
		m_writer_all.write(utf8Head);
		m_writer_all.write(new tagCommon().toCSVHead().getBytes());
	}

	@Override
	public void processEnd() {
		// TODO Auto-generated method stub
		try {
			m_writer_crcs.close();
			m_writer_netlog.close();
			m_writer_oce.close();
			m_writer_all.close();
			
			for(DataOutputStream csm_stream:m_csm_out_stream.values()){
				csm_stream.close();
			}
			
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	@Override
	public boolean processLine(String line, ParserLine parse){
		// TODO Auto-generated method stub
		tagCommon common = new tagCommon();
		
		if(!parse.getTag().contains(LOG_TAG)){
			return false;
		}
		
		return common.processLine(line, parse);
	}

	
	private void addCsmOutputStream(String csm,String line) throws IOException{
		DataOutputStream csm_stream;
		if(!m_csm_out_stream.containsKey(csm)){
			csm_stream = new DataOutputStream(new FileOutputStream(new File(m_csm_log_folder + csm + ".log")));
			csm_stream.write(utf8Head);
			m_csm_out_stream.put(csm, csm_stream);
		}else{
			csm_stream = m_csm_out_stream.get(csm);
		}
		
		csm_stream.write(new String(line + "\n").getBytes());
	}
	
}
